#include "ProtoField.h"
#include "ProtoFieldDescriptor.h"
#include "ProtoUtil.h"
#include "Message.h"

namespace miniproto
{

ProtoField::ProtoField()
{
	this->field_set_ = false;
	this->type_ = 0;
}

ProtoField::~ProtoField()
{ /*NULL*/ }

int ProtoField::ByteSize(const uint32_t number) const
{
	if (this->field_set_ == false)
		return 0;

	int tag_size = ::miniproto::uint32_byte_size(::miniproto::wire_tag(number, 0));
	int byte_size = 0;
	uint8_t base_type = ::miniproto::base_field_type(this->type_);
	if (::miniproto::is_array_field(this->type_))
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				byte_size += (this->bool_list_->size() * tag_size);
				byte_size += this->bool_byte_size(this->bool_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				byte_size += (this->int32_list_->size() * tag_size);
				byte_size += this->int32_byte_size(this->int32_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				byte_size += (this->int64_list_->size() * tag_size);
				byte_size += this->int64_byte_size(this->int64_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				byte_size += (this->uint32_list_->size() * tag_size);
				byte_size += this->uint32_byte_size(this->uint32_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				byte_size += (this->uint64_list_->size() * tag_size);
				byte_size += this->uint64_byte_size(this->uint64_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				byte_size += (this->float_list_->size() * tag_size);
				byte_size += this->float_byte_size(this->float_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				byte_size += (this->double_list_->size() * tag_size);
				byte_size += this->double_byte_size(this->double_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				byte_size += (this->string_list_->size() * tag_size);
				byte_size += this->string_byte_size(this->string_list_);
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				byte_size += (this->message_list_->size() * tag_size);
				byte_size += this->message_byte_size(this->message_list_);
				break;
			default:
				break;
		}
	}
	else
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				byte_size += tag_size;
				byte_size += this->bool_byte_size(this->bool_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				byte_size += tag_size;
				byte_size += this->int32_byte_size(this->int32_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				byte_size += tag_size;
				byte_size += this->int64_byte_size(this->int64_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				byte_size += tag_size;
				byte_size += this->uint32_byte_size(this->uint32_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				byte_size += tag_size;
				byte_size += this->uint64_byte_size(this->uint64_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				byte_size += tag_size;
				byte_size += this->float_byte_size(this->float_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				byte_size += tag_size;
				byte_size += this->double_byte_size(this->double_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				byte_size += tag_size;
				byte_size += this->string_byte_size(this->string_val_);
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				byte_size += tag_size;
				byte_size += this->message_byte_size(this->message_val_);
				break;
			default:
				break;
		}
	}
	return byte_size;
}

int ProtoField::bool_byte_size(const bool *val) const
{
	return 1;
}

int ProtoField::bool_byte_size(const BoolList *list) const
{
	return int(list->size());
}

int ProtoField::int32_byte_size(const int32_t *val) const
{
	if (*val < 0)
		return 10;
	uint32_t uval = static_cast<uint32_t>(*val);
	return this->uint32_byte_size(&uval);
}

int ProtoField::int32_byte_size(const Int32List *list) const
{
	int size = 0;
	for (Int32List::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		size += this->int32_byte_size(&(*iter));
	}
	return size;
}

int ProtoField::uint32_byte_size(const uint32_t *val) const
{
	return ::miniproto::uint32_byte_size(*val);
}

int ProtoField::uint32_byte_size(const UInt32List *list) const
{
	int size = 0;
	for (UInt32List::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		size += this->uint32_byte_size(&(*iter));
	}
	return size;
}

int ProtoField::int64_byte_size(const int64_t *val) const
{
	uint64_t uval = static_cast<uint64_t>(*val);
	return this->uint64_byte_size(&uval);
}

int ProtoField::int64_byte_size(const Int64List *list) const
{
	int size = 0;
	for (Int64List::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		size += this->int64_byte_size(&(*iter));
	}
	return size;
}
int ProtoField::uint64_byte_size(const uint64_t *val) const
{
	if (*val < (1ull << 35)) {
		if (*val < (1ull << 7)) {
			return 1;
		} else if (*val < (1ull << 14)) {
			return 2;
		} else if (*val < (1ull << 21)) {
			return 3;
		} else if (*val < (1ull << 28)) {
			return 4;
		} else {
			return 5;
		}
	} else {
		if (*val < (1ull << 42)) {
			return 6;
		} else if (*val < (1ull << 49)) {
			return 7;
		} else if (*val < (1ull << 56)) {
			return 8;
		} else if (*val < (1ull << 63)) {
			return 9;
		} else {
			return 10;
		}
	}
}

int ProtoField::uint64_byte_size(const UInt64List *list) const
{
	int size = 0;
	for (UInt64List::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		size += this->uint64_byte_size(&(*iter));
	}
	return size;
}

int ProtoField::float_byte_size(const float *val) const
{
	return 4;
}

int ProtoField::float_byte_size(const FloatList *list) const
{
	return int(list->size() * 4);
}

int ProtoField::double_byte_size(const double *val) const
{
	return 8;
}

int ProtoField::double_byte_size(const DoubleList *list) const
{
	return int(list->size() * 8);
}

int ProtoField::string_byte_size(const std::string *val) const
{
	uint32_t size = val->size();
	return int(this->uint32_byte_size(&size) + size);
}

int ProtoField::string_byte_size(const StringList *list) const
{
	int size = 0;
	for (StringList::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		size += this->string_byte_size(*iter);
	}
	return size;
}

int ProtoField::message_byte_size(const ::miniproto::Message *val) const
{
	uint32_t size = val->ByteSize();
	return int(this->uint32_byte_size(&size) + size);
}

int ProtoField::message_byte_size(const MessageList *list) const
{
	int size = 0;
	for (MessageList::const_iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		const ::miniproto::Message *message = *iter;
		size += this->message_byte_size(message);
	}
	return size;
}

void ProtoField::Clear()
{
	uint8_t base_type = ::miniproto::base_field_type(this->type_);
	if (::miniproto::is_array_field(this->type_))
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				{
					BoolList tmp;
					this->bool_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				{
					Int32List tmp;
					this->int32_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				{
					Int64List tmp;
					this->int64_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				{
					UInt32List tmp;
					this->uint32_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				{
					UInt64List tmp;
					this->uint64_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				{
					FloatList tmp;
					this->float_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				{
					DoubleList tmp;
					this->double_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				{
					for (StringList::iterator iter = this->string_list_->begin();
							iter != this->string_list_->end(); ++iter)
					{
						delete (*iter);
					}
					StringList tmp;
					this->string_list_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				{
					for (MessageList::iterator iter = this->message_list_->begin();
							iter != this->message_list_->end(); ++iter)
					{
						(*iter)->Destroy();
					}
					MessageList tmp;
					this->message_list_->swap(tmp);
				}
				break;
			default:
				break;
		}
	}
	else
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				*(this->bool_val_) = false;
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				*(this->int32_val_) = 0;
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				*(this->int64_val_) = 0;
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				*(this->uint32_val_) = 0;
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				*(this->uint64_val_) = 0;
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				*(this->float_val_) = 0.0;
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				*(this->double_val_) = 0.0;
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				{
					std::string tmp;
					this->string_val_->swap(tmp);
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				this->message_val_->Clear();
				break;
			default:
				break;
		}
	}
	this->field_set_ = false;
}

void ProtoField::set_field_set(const bool val)
{
	this->field_set_ = val;
}

bool ProtoField::is_field_set() const
{
	return this->field_set_;
}

int ProtoField::field_size() const
{
	if (this->field_set_ == false)
		return 0;

	uint8_t base_type = ::miniproto::base_field_type(this->type_);
	if (::miniproto::is_array_field(this->type_))
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				return this->bool_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				return this->int32_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				return this->int64_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				return this->uint32_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				return this->uint64_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				return this->float_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				return this->double_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				return this->string_list_->size();
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				return this->message_list_->size();
				break;
			default:
				break;
		}
		return 0;
	}

	return 1;
}

uint8_t ProtoField::field_type() const
{
	return this->type_;
}

void ProtoField::init_field_bool(bool *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::BOOL;
	this->bool_val_ = point;
}

void ProtoField::init_field_int32(int32_t *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::INT32;
	this->int32_val_ = point;
}

void ProtoField::init_field_int64(int64_t *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::INT64;
	this->int64_val_ = point;
}

void ProtoField::init_field_uint32(uint32_t *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::UINT32;
	this->uint32_val_ = point;
}

void ProtoField::init_field_uint64(uint64_t *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::UINT64;
	this->uint64_val_ = point;
}

void ProtoField::init_field_float(float *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::FLOAT;
	this->float_val_ = point;
}

void ProtoField::init_field_double(double *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::DOUBLE;
	this->double_val_ = point;
}

void ProtoField::init_field_string(::std::string *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::STRING;
	this->string_val_ = point;
}

void ProtoField::init_field_bytes(::std::string *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::BYTES;
	this->string_val_ = point;
}

void ProtoField::init_field_message(::miniproto::Message *point)
{
	this->type_ = ::miniproto::ProtoFieldDescriptor::MESSAGE;
	this->message_val_ = point;
}

void ProtoField::init_field_bool_list(BoolList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::BOOL | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->bool_list_ = point;
}

void ProtoField::init_field_int32_list(Int32List *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::INT32 | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->int32_list_ = point;
}

void ProtoField::init_field_int64_list(Int64List *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::INT64 | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->int64_list_ = point;
}

void ProtoField::init_field_uint32_list(UInt32List *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::UINT32 | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->uint32_list_ = point;
}

void ProtoField::init_field_uint64_list(UInt64List *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::UINT64 | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->uint64_list_ = point;
}

void ProtoField::init_field_float_list(FloatList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::FLOAT | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->float_list_ = point;
}

void ProtoField::init_field_double_list(DoubleList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::DOUBLE | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->double_list_ = point;
}

void ProtoField::init_field_string_list(StringList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::STRING | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->string_list_ = point;
}

void ProtoField::init_field_bytes_list(StringList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::BYTES | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->string_list_ = point;
}

void ProtoField::init_field_message_list(MessageList *point)
{
	this->type_ = (::miniproto::ProtoFieldDescriptor::MESSAGE | ::miniproto::ProtoFieldDescriptor::ARRAY);
	this->message_list_ = point;
}

void ProtoField::set_field_bool(const bool val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::BOOL)
	{
		*(this->bool_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_int32(const int32_t val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::INT32)
	{
		*(this->int32_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_int64(const int64_t val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::INT64)
	{
		*(this->int64_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_uint32(const uint32_t val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::UINT32)
	{
		*(this->uint32_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_uint64(const uint64_t val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::UINT64)
	{
		*(this->uint64_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_float(const float val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::FLOAT)
	{
		*(this->float_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_double(const double val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::DOUBLE)
	{
		*(this->double_val_) = val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_string(::std::string *val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::STRING ||
			this->type_ == ::miniproto::ProtoFieldDescriptor::BYTES)
	{
		*(this->string_val_) = *val;
		this->set_field_set(true);
	}
}

void ProtoField::set_field_message(::miniproto::Message *val)
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::MESSAGE)
	{
		this->message_val_->CopyFrom(*val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_bool(const bool val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::BOOL | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->bool_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_int32(const int32_t val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::INT32 | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->int32_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_int64(const int64_t val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::INT64 | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->int64_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_uint32(const uint32_t val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::UINT32 | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->uint32_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_uint64(const uint64_t val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::UINT64 | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->uint64_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_float(const float val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::FLOAT | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->float_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_double(const double val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::DOUBLE | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->double_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_string(::std::string *val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::STRING | ::miniproto::ProtoFieldDescriptor::ARRAY) ||
			this->type_ == (::miniproto::ProtoFieldDescriptor::BYTES | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->string_list_->push_back(val);
		this->set_field_set(true);
	}
}

void ProtoField::add_field_message(::miniproto::Message *val)
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::MESSAGE | ::miniproto::ProtoFieldDescriptor::ARRAY))
	{
		this->message_list_->push_back(val);
		this->set_field_set(true);
	}
}

bool ProtoField::get_field_bool() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::BOOL)
		return *(this->bool_val_);
	return false;
}

int32_t ProtoField::get_field_int32() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::INT32)
		return *(this->int32_val_);
	return 0;
}

int64_t ProtoField::get_field_int64() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::INT64)
		return *(this->int64_val_);
	return 0;
}

uint32_t ProtoField::get_field_uint32() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::UINT32)
		return *(this->uint32_val_);
	return 0;
}

uint64_t ProtoField::get_field_uint64() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::UINT64)
		return *(this->uint64_val_);
	return 0;
}

float ProtoField::get_field_float() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::FLOAT)
		return *(this->float_val_);
	return 0;
}

double ProtoField::get_field_double() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::DOUBLE)
		return *(this->double_val_);
	return 0;
}

::std::string *ProtoField::get_field_string()
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::STRING ||
			this->type_ == ::miniproto::ProtoFieldDescriptor::BYTES)
		return this->string_val_;
	return NULL;
}

::miniproto::Message *ProtoField::get_field_message()
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::MESSAGE)
		return this->message_val_;
	return NULL;
}

const ::std::string *ProtoField::get_field_string() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::STRING ||
			this->type_ == ::miniproto::ProtoFieldDescriptor::BYTES)
		return this->string_val_;
	return NULL;
}

const ::miniproto::Message *ProtoField::get_field_message() const
{
	if (this->type_ == ::miniproto::ProtoFieldDescriptor::MESSAGE)
		return this->message_val_;
	return NULL;
}

const ProtoField::BoolList *ProtoField::get_field_bool_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::BOOL | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->bool_list_;
	return NULL;
}

const ProtoField::Int32List *ProtoField::get_field_int32_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::INT32 | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->int32_list_;
	return NULL;
}

const ProtoField::Int64List *ProtoField::get_field_int64_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::INT64 | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->int64_list_;
	return NULL;
}

const ProtoField::UInt32List *ProtoField::get_field_uint32_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::UINT32 | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->uint32_list_;
	return NULL;
}

const ProtoField::UInt64List *ProtoField::get_field_uint64_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::UINT64 | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->uint64_list_;
	return NULL;
}

const ProtoField::FloatList *ProtoField::get_field_float_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::FLOAT | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->float_list_;
	return NULL;
}

const ProtoField::DoubleList *ProtoField::get_field_double_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::DOUBLE | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->double_list_;
	return NULL;
}

const ProtoField::StringList *ProtoField::get_field_string_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::STRING | ::miniproto::ProtoFieldDescriptor::ARRAY) ||
			this->type_ == (::miniproto::ProtoFieldDescriptor::BYTES | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->string_list_;
	return NULL;
}

const ProtoField::MessageList *ProtoField::get_field_message_list() const
{
	if (this->type_ == (::miniproto::ProtoFieldDescriptor::MESSAGE | ::miniproto::ProtoFieldDescriptor::ARRAY))
		return this->message_list_;
	return NULL;
}

void ProtoField::copy(const ProtoField &field)
{
	this->field_set_ = field.field_set_;
	this->type_ = field.type_;
	uint8_t base_type = ::miniproto::base_field_type(this->type_);
	if (::miniproto::is_array_field(this->type_))
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				*(this->bool_list_) = *(field.get_field_bool_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				*(this->int32_list_) = *(field.get_field_int32_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				*(this->int64_list_) = *(field.get_field_int64_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				*(this->uint32_list_) = *(field.get_field_uint32_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				*(this->uint64_list_) = *(field.get_field_uint64_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				*(this->float_list_) = *(field.get_field_float_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				*(this->double_list_) = *(field.get_field_double_list());
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				for (StringList::iterator iter = this->string_list_->begin();
						iter != this->string_list_->end(); ++iter)
				{
					delete (*iter);
				}
				this->string_list_->resize(field.get_field_string_list()->size());
				for (uint32_t i = 0; i < this->string_list_->size(); ++i)
				{
					std::string *val = new std::string(*(field.get_field_string_list()->at(i)));
					(*(this->string_list_))[i] = val;
				}
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				for (MessageList::iterator iter = this->message_list_->begin();
						iter != this->message_list_->end(); ++iter)
				{
					(*iter)->Destroy();
				}
				this->message_list_->resize(field.get_field_message_list()->size());
				for (uint32_t i = 0; i < this->message_list_->size(); ++i)
				{
					::miniproto::Message *message = field.get_field_message_list()->at(i)->New();
					message->MergeFrom(*(field.get_field_message_list()->at(i)));
					(*(this->message_list_))[i] = message;
				}
				break;
			default:
				break;
		}
	}
	else
	{
		switch(base_type)
		{
			case ::miniproto::ProtoFieldDescriptor::BOOL:
				*(this->bool_val_) = field.get_field_bool();
				break;
			case ::miniproto::ProtoFieldDescriptor::INT32:
				*(this->int32_val_) = field.get_field_int32();
				break;
			case ::miniproto::ProtoFieldDescriptor::INT64:
				*(this->int64_val_) = field.get_field_int64();
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT32:
				*(this->uint32_val_) = field.get_field_uint32();
				break;
			case ::miniproto::ProtoFieldDescriptor::UINT64:
				*(this->uint64_val_) = field.get_field_uint64();
				break;
			case ::miniproto::ProtoFieldDescriptor::FLOAT:
				*(this->float_val_) = field.get_field_float();
				break;
			case ::miniproto::ProtoFieldDescriptor::DOUBLE:
				*(this->double_val_) = field.get_field_double();
				break;
			case ::miniproto::ProtoFieldDescriptor::STRING:
			case ::miniproto::ProtoFieldDescriptor::BYTES:
				*(this->string_val_) = *(field.get_field_string());
				break;
			case ::miniproto::ProtoFieldDescriptor::MESSAGE:
				this->message_val_->CopyFrom(*(field.get_field_message()));
				break;
			default:
				break;
		}
	}
}

} // namespace miniproto
